1   /*                        __    __  __  __    __  ___
2    *                       \  \  /  /    \  \  /  /  __/
3    *                        \  \/  /  /\  \  \/  /  /
4    *                         \____/__/  \__\____/__/.ɪᴏ
5    * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
6    */
7   package io.vavr.collection;
8   
9   import io.vavr.Function1;
10  import io.vavr.Tuple;
11  import io.vavr.Tuple2;
12  import io.vavr.control.Option;
13  import org.assertj.core.api.IterableAssert;
14  import org.junit.Test;
15  
16  import java.math.BigDecimal;
17  import java.nio.charset.StandardCharsets;
18  import java.security.MessageDigest;
19  import java.util.*;
20  import java.util.Set;
21  import java.util.function.BiConsumer;
22  import java.util.function.BinaryOperator;
23  import java.util.function.Function;
24  import java.util.function.Supplier;
25  import java.util.regex.Pattern;
26  import java.util.stream.Collector;
27  
28  import static java.util.Arrays.asList;
29  import static io.vavr.API.Some;
30  import static io.vavr.Serializables.deserialize;
31  import static io.vavr.Serializables.serialize;
32  
33  public abstract class AbstractMapTest extends AbstractTraversableTest {
34  
35      @Override
36      protected <T> IterableAssert<T> assertThat(Iterable<T> actual) {
37          return new IterableAssert<T>(actual) {
38              @Override
39              public IterableAssert<T> isEqualTo(Object obj) {
40                  @SuppressWarnings("unchecked")
41                  final Iterable<T> expected = (Iterable<T>) obj;
42                  final java.util.Map<T, Integer> actualMap = countMap(actual);
43                  final java.util.Map<T, Integer> expectedMap = countMap(expected);
44                  assertThat(actualMap.size()).isEqualTo(expectedMap.size());
45                  actualMap.forEach((k, v) -> assertThat(v).isEqualTo(expectedMap.get(k)));
46                  return this;
47              }
48  
49              private java.util.Map<T, Integer> countMap(Iterable<? extends T> it) {
50                  final java.util.HashMap<T, Integer> cnt = new java.util.HashMap<>();
51                  it.forEach(i -> cnt.merge(i, 1, (v1, v2) -> v1 + v2));
52                  return cnt;
53              }
54          };
55      }
56  
57      @Override
58      protected <T> Collector<T, ArrayList<T>, IntMap<T>> collector() {
59          final Collector<Tuple2<Integer, T>, ArrayList<Tuple2<Integer, T>>, ? extends Map<Integer, T>> mapCollector = mapCollector();
60          return new Collector<T, ArrayList<T>, IntMap<T>>() {
61              @Override
62              public Supplier<ArrayList<T>> supplier() {
63                  return ArrayList::new;
64              }
65  
66              @Override
67              public BiConsumer<ArrayList<T>, T> accumulator() {
68                  return ArrayList::add;
69              }
70  
71              @Override
72              public BinaryOperator<ArrayList<T>> combiner() {
73                  return (left, right) -> fromTuples(mapCollector.combiner().apply(toTuples(left), toTuples(right)));
74              }
75  
76              @Override
77              public Function<ArrayList<T>, IntMap<T>> finisher() {
78                  return AbstractMapTest.this::ofAll;
79              }
80  
81              @Override
82              public Set<Characteristics> characteristics() {
83                  return mapCollector.characteristics();
84              }
85  
86              private ArrayList<Tuple2<Integer, T>> toTuples(java.util.List<T> list) {
87                  final ArrayList<Tuple2<Integer, T>> result = new ArrayList<>();
88                  Stream.ofAll(list)
89                          .zipWithIndex()
90                          .map(tu -> Tuple.of(tu._2, tu._1))
91                          .forEach(result::add);
92                  return result;
93              }
94  
95              private ArrayList<T> fromTuples(java.util.List<Tuple2<Integer, T>> list) {
96                  final ArrayList<T> result = new ArrayList<>();
97                  Stream.ofAll(list)
98                          .map(tu -> tu._2)
99                          .forEach(result::add);
100                 return result;
101             }
102         };
103     }
104 
105     @Override
106     protected <T> IntMap<T> empty() {
107         return IntMap.of(emptyMap());
108     }
109 
110     @Override
111     protected boolean emptyShouldBeSingleton() {
112         return false;
113     }
114 
115     private <T> Map<Integer, T> emptyInt() {
116         return emptyMap();
117     }
118 
119     protected Map<Integer, Integer> emptyIntInt() {
120         return emptyMap();
121     }
122 
123     private Map<Integer, String> emptyIntString() {
124         return emptyMap();
125     }
126 
127     protected abstract String className();
128 
129     abstract <T1, T2> java.util.Map<T1, T2> javaEmptyMap();
130 
131     protected abstract <T1 extends Comparable<? super T1>, T2> Map<T1, T2> emptyMap();
132 
133     protected boolean emptyMapShouldBeSingleton() {
134         return true;
135     }
136 
137     protected abstract <T> Collector<Tuple2<Integer, T>, ArrayList<Tuple2<Integer, T>>, ? extends Map<Integer, T>> mapCollector();
138 
139     @SuppressWarnings("unchecked")
140     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOfTuples(Tuple2<? extends K, ? extends V>... entries);
141 
142     @SuppressWarnings("unchecked")
143     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOfEntries(java.util.Map.Entry<? extends K, ? extends V>... entries);
144 
145     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1);
146 
147     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2);
148 
149     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3);
150 
151     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4);
152 
153     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5);
154 
155     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6);
156 
157     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7);
158 
159     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8);
160 
161     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9);
162 
163     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10);
164 
165     protected abstract <T, K extends Comparable<? super K>, V> Map<K, V> mapOf(java.util.stream.Stream<? extends T> stream,
166             Function<? super T, ? extends K> keyMapper,
167             Function<? super T, ? extends V> valueMapper);
168 
169     protected abstract <T, K extends Comparable<? super K>, V> Map<K, V> mapOf(java.util.stream.Stream<? extends T> stream,
170             Function<? super T, Tuple2<? extends K, ? extends V>> f);
171 
172     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOfNullKey(K k1, V v1, K k2, V v2);
173 
174     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapOfNullKey(K k1, V v1, K k2, V v2, K k3, V v3);
175 
176     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapTabulate(int n, Function<? super Integer, ? extends Tuple2<? extends K, ? extends V>> f);
177 
178     protected abstract <K extends Comparable<? super K>, V> Map<K, V> mapFill(int n, Supplier<? extends Tuple2<? extends K, ? extends V>> s);
179 
180     @Override
181     protected boolean useIsEqualToInsteadOfIsSameAs() {
182         return true;
183     }
184 
185     @Override
186     protected int getPeekNonNilPerformingAnAction() {
187         return 1;
188     }
189 
190     @Override
191     protected <T> IntMap<T> of(T element) {
192         Map<Integer, T> map = emptyMap();
193         map = map.put(0, element);
194         return IntMap.of(map);
195     }
196 
197     @SuppressWarnings("unchecked")
198     @Override
199     protected <T> IntMap<T> of(T... elements) {
200         Map<Integer, T> map = emptyMap();
201         for (T element : elements) {
202             map = map.put(map.size(), element);
203         }
204         return IntMap.of(map);
205     }
206 
207     @Override
208     protected <T> IntMap<T> ofAll(Iterable<? extends T> elements) {
209         Map<Integer, T> map = emptyMap();
210         for (T element : elements) {
211             map = map.put(map.size(), element);
212         }
213         return IntMap.of(map);
214     }
215 
216     @Override
217     protected <T extends Comparable<? super T>> IntMap<T> ofJavaStream(java.util.stream.Stream<? extends T> javaStream) {
218         return ofAll(io.vavr.collection.Iterator.ofAll(javaStream.iterator()));
219     }
220 
221     @Override
222     protected IntMap<Boolean> ofAll(boolean... elements) {
223         return ofAll(io.vavr.collection.Iterator.ofAll(elements));
224     }
225 
226     @Override
227     protected IntMap<Byte> ofAll(byte... elements) {
228         return ofAll(io.vavr.collection.Iterator.ofAll(elements));
229     }
230 
231     @Override
232     protected IntMap<Character> ofAll(char... elements) {
233         return ofAll(io.vavr.collection.Iterator.ofAll(elements));
234     }
235 
236     @Override
237     protected IntMap<Double> ofAll(double... elements) {
238         return ofAll(io.vavr.collection.Iterator.ofAll(elements));
239     }
240 
241     @Override
242     protected IntMap<Float> ofAll(float... elements) {
243         return ofAll(io.vavr.collection.Iterator.ofAll(elements));
244     }
245 
246     @Override
247     protected IntMap<Integer> ofAll(int... elements) {
248         return ofAll(io.vavr.collection.Iterator.ofAll(elements));
249     }
250 
251     @Override
252     protected IntMap<Long> ofAll(long... elements) {
253         return ofAll(io.vavr.collection.Iterator.ofAll(elements));
254     }
255 
256     @Override
257     protected IntMap<Short> ofAll(short... elements) {
258         return ofAll(io.vavr.collection.Iterator.ofAll(elements));
259     }
260 
261     @Override
262     protected <T> IntMap<T> tabulate(int n, Function<? super Integer, ? extends T> f) {
263         Map<Integer, T> map = emptyMap();
264         for (int i = 0; i < n; i++) {
265             map = map.put(map.size(), f.apply(i));
266         }
267         return IntMap.of(map);
268     }
269 
270     @Override
271     protected <T> IntMap<T> fill(int n, Supplier<? extends T> s) {
272         return tabulate(n, anything -> s.get());
273     }
274 
275     // -- narrow
276 
277     @Test
278     public void shouldNarrowMap() {
279         final Map<Integer, Double> int2doubleMap = mapOf(1, 1.0d);
280         final Map<Number, Number> number2numberMap = Map.narrow(int2doubleMap);
281         final int actual = number2numberMap.put(new BigDecimal("2"), new BigDecimal("2.0")).values().sum().intValue();
282         assertThat(actual).isEqualTo(3);
283     }
284 
285     // -- construction
286 
287     @Test
288     public void shouldBeTheSame() {
289         assertThat(mapOf(1, 2)).isEqualTo(emptyInt().put(1, 2));
290     }
291 
292     protected static java.util.Map.Entry<Integer, String> asJavaEntry(int key, String value) {
293         return new java.util.AbstractMap.SimpleEntry<>(key, value);
294     }
295 
296     @SafeVarargs
297     protected final <K, V> java.util.Map<K, V> asJavaMap(java.util.Map.Entry<K, V>... entries) {
298         final java.util.Map<K, V> results = javaEmptyMap();
299         for (java.util.Map.Entry<K, V> entry : entries) {
300             results.put(entry.getKey(), entry.getValue());
301         }
302         return results;
303     }
304 
305     @Test
306     public void shouldConstructFrom1Entry() {
307         final Map<Integer, String> actual = mapOf(1, "1");
308         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"));
309         assertThat(actual.toJavaMap()).isEqualTo(expected);
310     }
311 
312     @Test
313     public void shouldConstructFrom2Entries() {
314         final Map<Integer, String> actual = mapOf(1, "1", 2, "2");
315         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"));
316         assertThat(actual.toJavaMap()).isEqualTo(expected);
317     }
318 
319     @Test
320     public void shouldConstructFrom3Entries() {
321         final Map<Integer, String> actual = mapOf(1, "1", 2, "2", 3, "3");
322         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"));
323         assertThat(actual.toJavaMap()).isEqualTo(expected);
324     }
325 
326     @Test
327     public void shouldConstructFrom4Entries() {
328         final Map<Integer, String> actual = mapOf(1, "1", 2, "2", 3, "3", 4, "4");
329         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"), asJavaEntry(4, "4"));
330         assertThat(actual.toJavaMap()).isEqualTo(expected);
331     }
332 
333     @Test
334     public void shouldConstructFrom5Entries() {
335         final Map<Integer, String> actual = mapOf(1, "1", 2, "2", 3, "3", 4, "4", 5, "5");
336         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"), asJavaEntry(4, "4"), asJavaEntry(5, "5"));
337         assertThat(actual.toJavaMap()).isEqualTo(expected);
338     }
339 
340     @Test
341     public void shouldConstructFrom6Entries() {
342         final Map<Integer, String> actual = mapOf(1, "1", 2, "2", 3, "3", 4, "4", 5, "5", 6, "6");
343         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"), asJavaEntry(4, "4"), asJavaEntry(5, "5"), asJavaEntry(6, "6"));
344         assertThat(actual.toJavaMap()).isEqualTo(expected);
345     }
346 
347     @Test
348     public void shouldConstructFrom7Entries() {
349         final Map<Integer, String> actual = mapOf(1, "1", 2, "2", 3, "3", 4, "4", 5, "5", 6, "6", 7, "7");
350         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"), asJavaEntry(4, "4"), asJavaEntry(5, "5"), asJavaEntry(6, "6"), asJavaEntry(7, "7"));
351         assertThat(actual.toJavaMap()).isEqualTo(expected);
352     }
353 
354     @Test
355     public void shouldConstructFrom8Entries() {
356         final Map<Integer, String> actual = mapOf(1, "1", 2, "2", 3, "3", 4, "4", 5, "5", 6, "6", 7, "7", 8, "8");
357         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"), asJavaEntry(4, "4"), asJavaEntry(5, "5"), asJavaEntry(6, "6"), asJavaEntry(7, "7"), asJavaEntry(8, "8"));
358         assertThat(actual.toJavaMap()).isEqualTo(expected);
359     }
360 
361     @Test
362     public void shouldConstructFrom9Entries() {
363         final Map<Integer, String> actual = mapOf(1, "1", 2, "2", 3, "3", 4, "4", 5, "5", 6, "6", 7, "7", 8, "8", 9, "9");
364         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"), asJavaEntry(4, "4"), asJavaEntry(5, "5"), asJavaEntry(6, "6"), asJavaEntry(7, "7"), asJavaEntry(8, "8"), asJavaEntry(9, "9"));
365         assertThat(actual.toJavaMap()).isEqualTo(expected);
366     }
367 
368     @Test
369     public void shouldConstructFrom10Entries() {
370         final Map<Integer, String> actual = mapOf(1, "1", 2, "2", 3, "3", 4, "4", 5, "5", 6, "6", 7, "7", 8, "8", 9, "9", 10, "10");
371         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"), asJavaEntry(4, "4"), asJavaEntry(5, "5"), asJavaEntry(6, "6"), asJavaEntry(7, "7"), asJavaEntry(8, "8"), asJavaEntry(9, "9"), asJavaEntry(10, "10"));
372         assertThat(actual.toJavaMap()).isEqualTo(expected);
373     }
374 
375     @Test
376     public void shouldConstructFromJavaStream() {
377         final java.util.stream.Stream<Integer> javaStream = java.util.stream.Stream.of(1, 2, 3);
378         final Map<String, Integer> map = mapOf(javaStream, String::valueOf, Function.identity());
379         assertThat(map).isEqualTo(this.<String, Integer> emptyMap().put("1", 1).put("2", 2).put("3", 3));
380     }
381 
382     @Test
383     public void shouldConstructFromJavaStreamEntries() {
384         final java.util.stream.Stream<Integer> javaStream = java.util.stream.Stream.of(1, 2, 3);
385         final Map<String, Integer> map = mapOf(javaStream, i -> Tuple.of(String.valueOf(i), i));
386         assertThat(map).isEqualTo(this.<String, Integer> emptyMap().put("1", 1).put("2", 2).put("3", 3));
387     }
388 
389     @Test
390     @SuppressWarnings("unchecked")
391     public void shouldConstructFromUtilEntries() {
392         final Map<Integer, String> actual = mapOfEntries(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"));
393         final Map<Integer, String> expected = this.<Integer, String>emptyMap().put(1, "1").put(2, "2").put(3, "3");
394         assertThat(actual).isEqualTo(expected);
395     }
396 
397     @Test
398     @SuppressWarnings("unchecked")
399     public void shouldConstructFromEntries() {
400         final Map<String, Integer> actual = mapOfTuples(Map.entry("1", 1), Map.entry("2", 2), Map.entry("3", 3));
401         final Map<String, Integer> expected = this.<String, Integer>emptyMap().put("1", 1).put("2", 2).put("3", 3);
402         assertThat(actual).isEqualTo(expected);
403     }
404 
405     @Test
406     public void shouldConstructFromPairs() {
407         final Map<String, Integer> actual = mapOf("1", 1, "2", 2, "3", 3);
408         final Map<String, Integer> expected = this.<String, Integer>emptyMap().put("1", 1).put("2", 2).put("3", 3);
409         assertThat(actual).isEqualTo(expected);
410     }
411 
412     // -- equality
413 
414     @Test
415     public void shouldObeyEqualityConstraints() {
416 
417         // sequential collections
418         assertThat(emptyMap().equals(io.vavr.collection.HashMap.empty())).isTrue();
419         assertThat(mapOf(1, "a").equals(io.vavr.collection.HashMap.of(1, "a"))).isTrue();
420         assertThat(mapOf(1, "a", 2, "b", 3, "c").equals(io.vavr.collection.HashMap.of(1, "a", 2, "b",3, "c"))).isTrue();
421         assertThat(mapOf(1, "a", 2, "b", 3, "c").equals(io.vavr.collection.HashMap.of(3, "c", 2, "b",1, "a"))).isTrue();
422 
423         // other classes
424         assertThat(empty().equals(io.vavr.collection.List.empty())).isFalse();
425         assertThat(empty().equals(HashMultimap.withSeq().empty())).isFalse();
426         assertThat(empty().equals(io.vavr.collection.HashSet.empty())).isFalse();
427 
428         assertThat(empty().equals(LinkedHashMultimap.withSeq().empty())).isFalse();
429         assertThat(empty().equals(io.vavr.collection.LinkedHashSet.empty())).isFalse();
430 
431         assertThat(empty().equals(TreeMultimap.withSeq().empty())).isFalse();
432         assertThat(empty().equals(io.vavr.collection.TreeSet.empty())).isFalse();
433     }
434 
435     // -- head
436 
437     @Test(expected = NoSuchElementException.class)
438     public void shouldThrowWhenHeadEmpty() {
439         emptyMap().head();
440     }
441 
442     // -- init
443 
444     @Test(expected = UnsupportedOperationException.class)
445     public void shouldThrowWhenInitEmpty() {
446         emptyMap().init();
447     }
448 
449     // -- tail
450 
451     @Test(expected = UnsupportedOperationException.class)
452     public void shouldThrowWhenTailEmpty() {
453         emptyMap().tail();
454     }
455 
456     // -- toString
457 
458     @Test
459     public void shouldMakeString() {
460         assertThat(emptyMap().toString()).isEqualTo(className() + "()");
461         assertThat(emptyInt().put(1, 2).toString()).isEqualTo(className() + "(" + Tuple.of(1, 2) + ")");
462     }
463 
464     // -- toJavaMap
465 
466     @Test
467     public void shouldConvertToJavaMap() {
468         final Map<Integer, String> actual = mapOf(1, "1", 2, "2", 3, "3");
469         final java.util.Map<Integer, String> expected = asJavaMap(asJavaEntry(1, "1"), asJavaEntry(2, "2"), asJavaEntry(3, "3"));
470         assertThat(actual.toJavaMap()).isEqualTo(expected);
471     }
472 
473     // -- apply
474 
475     @Test
476     public void shouldApplyExistingKey() {
477         assertThat(emptyInt().put(1, 2).apply(1)).isEqualTo(2);
478     }
479 
480     @Test(expected = NoSuchElementException.class)
481     public void shouldApplyNonExistingKey() {
482         emptyInt().put(1, 2).apply(3);
483     }
484 
485     // -- contains
486 
487     @Test
488     public void shouldFindKey() {
489         assertThat(emptyInt().put(1, 2).containsKey(1)).isTrue();
490         assertThat(emptyInt().put(1, 2).containsKey(2)).isFalse();
491     }
492 
493     @Test
494     public void shouldFindValue() {
495         assertThat(emptyInt().put(1, 2).containsValue(2)).isTrue();
496         assertThat(emptyInt().put(1, 2).containsValue(1)).isFalse();
497     }
498 
499     @Test
500     public void shouldRecognizeNotContainedKeyValuePair() {
501         final io.vavr.collection.TreeMap<String, Integer> testee = io.vavr.collection.TreeMap.of(Tuple.of("one", 1));
502         assertThat(testee.contains(Tuple.of("one", 0))).isFalse();
503     }
504 
505     @Test
506     public void shouldRecognizeContainedKeyValuePair() {
507         final io.vavr.collection.TreeMap<String, Integer> testee = io.vavr.collection.TreeMap.of(Tuple.of("one", 1));
508         assertThat(testee.contains(Tuple.of("one", 1))).isTrue();
509     }
510 
511     // -- flatMap
512 
513     @SuppressWarnings("unchecked")
514     @Test
515     public void shouldFlatMapUsingBiFunction() {
516         final Map<Integer, Integer> testee = mapOfTuples(Tuple.of(1, 11), Tuple.of(2, 22), Tuple.of(3, 33));
517         final Map<String, String> actual = testee
518                 .flatMap((k, v) -> io.vavr.collection.List.of(Tuple.of(String.valueOf(k), String.valueOf(v)),
519                         Tuple.of(String.valueOf(k * 10), String.valueOf(v * 10))));
520         final Map<String, String> expected = mapOfTuples(Tuple.of("1", "11"), Tuple.of("10", "110"), Tuple.of("2", "22"),
521                 Tuple.of("20", "220"), Tuple.of("3", "33"), Tuple.of("30", "330"));
522         assertThat(actual).isEqualTo(expected);
523     }
524 
525     // -- keySet
526 
527     @Test
528     @SuppressWarnings("unchecked")
529     public void shouldReturnsKeySet() {
530         final io.vavr.collection.Set<Integer> actual = mapOfTuples(Tuple.of(1, 11), Tuple.of(2, 22), Tuple.of(3, 33)).keySet();
531         assertThat(actual).isEqualTo(io.vavr.collection.HashSet.of(1, 2, 3));
532     }
533 
534     // -- biMap
535 
536     @Test
537     public void shouldBiMapEmpty() {
538         assertThat(emptyInt().bimap(i -> i + 1, o -> o)).isEqualTo(io.vavr.collection.Vector.empty());
539     }
540 
541     @Test
542     public void shouldBiMapNonEmpty() {
543         final Seq<Tuple2<Integer, String>> expected = Stream.of(Tuple.of(2, "1!"), Tuple.of(3, "2!"));
544         final Seq<Tuple2<Integer, String>> actual = emptyInt().put(1, "1").put(2, "2").bimap(i -> i + 1, s -> s + "!").toStream();
545         assertThat(actual).isEqualTo(expected);
546     }
547 
548     // -- orElse
549     // DEV-Note: IntMap converts `other` to map
550 
551     @Override
552     @Test
553     public void shouldCaclEmptyOrElseSameOther() {
554         Iterable<Integer> other = of(42);
555         assertThat(empty().orElse(other)).isEqualTo(other);
556     }
557 
558     @Test
559     public void shouldCaclEmptyOrElseSameSupplier() {
560         Iterable<Integer> other = of(42);
561         Supplier<Iterable<Integer>> supplier = () -> other;
562         assertThat(empty().orElse(supplier)).isEqualTo(other);
563     }
564 
565     // -- map
566 
567     @Test
568     public void shouldMapEmpty() {
569         assertThat(emptyInt().map(Tuple2::_1)).isEqualTo(io.vavr.collection.Vector.empty());
570     }
571 
572     @Test
573     public void shouldMapNonEmpty() {
574         final Seq<Integer> expected = io.vavr.collection.Vector.of(1, 2);
575         final Seq<Integer> actual = emptyInt().put(1, "1").put(2, "2").map(Tuple2::_1);
576         assertThat(actual).isEqualTo(expected);
577     }
578 
579     @Test
580     public void shouldReturnEmptySetWhenAskedForTuple2SetOfAnEmptyMap() {
581         assertThat(emptyMap().toSet()).isEqualTo(io.vavr.collection.HashSet.empty());
582     }
583 
584     @Test
585     public void shouldReturnTuple2SetOfANonEmptyMap() {
586         assertThat(emptyInt().put(1, "1").put(2, "2").toSet()).isEqualTo(io.vavr.collection.HashSet.of(Tuple.of(1, "1"), Tuple.of(2, "2")));
587     }
588 
589     @Test
590     public void shouldReturnModifiedKeysMap() {
591         final Map<String, String> actual = emptyIntString().put(1, "1").put(2, "2").mapKeys(k -> k * 12).mapKeys(Integer::toHexString).mapKeys(String::toUpperCase);
592         final Map<String, String> expected = this.<String, String> emptyMap().put("C", "1").put("18", "2");
593         assertThat(actual).isEqualTo(expected);
594     }
595 
596     @Test
597     public void shouldReturnModifiedKeysMapWithNonUniqueMapper() {
598         final Map<Integer, String> actual = emptyIntString()
599                 .put(1, "1").put(2, "2").put(3, "3")
600                 .mapKeys(k -> k * 118).mapKeys(Integer::toHexString).mapKeys(AbstractMapTest::md5).mapKeys(String::length);
601         assertThat(actual).hasSize(1);
602         assertThat(actual.values()).hasSize(1);
603         //In different cases (based on items order) transformed map may contain different values
604         assertThat(actual.values().head()).isIn("1", "2", "3");
605     }
606 
607     public static String md5(String src) {
608         try {
609             final MessageDigest md = MessageDigest.getInstance("MD5");
610             md.update(src.getBytes(StandardCharsets.UTF_8));
611             return toHexString(md.digest());
612         } catch (Exception e) {
613             throw new IllegalStateException(e);
614         }
615     }
616 
617     /**
618      * Returns a string in the hexadecimal format.
619      *
620      * @param bytes the converted bytes
621      * @return the hexadecimal string representing the bytes data
622      * @throws IllegalArgumentException if the byte array is null
623      */
624     public static String toHexString(byte[] bytes) {
625         if (bytes == null) {
626             throw new IllegalArgumentException("byte array must not be null");
627         }
628 
629         final StringBuilder hex = new StringBuilder(bytes.length * 2);
630         for (byte aByte : bytes) {
631             hex.append(Character.forDigit((aByte & 0XF0) >> 4, 16));
632             hex.append(Character.forDigit((aByte & 0X0F), 16));
633         }
634         return hex.toString();
635     }
636 
637     @Test
638     public void shouldReturnModifiedKeysMapWithNonUniqueMapperAndMergedValus() {
639         final Map<Integer, String> actual = emptyIntString()
640                 .put(1, "1").put(2, "2").put(3, "3")
641                 .mapKeys(k -> k * 118).mapKeys(Integer::toHexString).mapKeys(AbstractMapTest::md5)//Unique key mappers
642                 .mapKeys(String::length, (v1, v2) -> io.vavr.collection.List.of(v1.split("#")).append(v2).sorted().mkString("#"));
643         final Map<Integer, String> expected = emptyIntString().put(32, "1#2#3");
644         assertThat(actual).isEqualTo(expected);
645     }
646 
647     @Test
648     public void shouldReturnModifiedValuesMap() {
649         assertThat(emptyIntString().put(1, "1").put(2, "2").mapValues(Integer::parseInt)).isEqualTo(emptyInt().put(1, 1).put(2, 2));
650     }
651 
652     @Test
653     public void shouldReturnListWithMappedValues() {
654         assertThat(emptyIntInt().put(1, 1).put(2, 2).iterator((a, b) -> a + b).toList()).isEqualTo(io.vavr.collection.List.of(2, 4));
655     }
656 
657     // -- merge(Map)
658 
659     @Test
660     public void shouldMerge() {
661         final Map<Integer, Integer> m1 = emptyIntInt().put(1, 1).put(2, 2);
662         final Map<Integer, Integer> m2 = emptyIntInt().put(1, 1).put(4, 4);
663         final Map<Integer, Integer> m3 = emptyIntInt().put(3, 3).put(4, 4);
664         assertThat(m1.merge(m2)).isEqualTo(emptyIntInt().put(1, 1).put(2, 2).put(4, 4));
665         assertThat(m1.merge(m3)).isEqualTo(emptyIntInt().put(1, 1).put(2, 2).put(3, 3).put(4, 4));
666     }
667 
668     @Test
669     public void shouldReturnSameMapWhenMergeNonEmptyWithEmpty() {
670         final Map<Integer, String> map = mapOf(1, "a", 2, "b", 3, "c");
671         assertThat(map.merge(emptyMap())).isSameAs(map);
672     }
673 
674     @Test
675     public void shouldReturnSameMapWhenMergeEmptyWithNonEmpty() {
676         final Map<Integer, String> map = mapOf(1, "a", 2, "b", 3, "c");
677         if (map.isOrdered()) {
678             assertThat(this.<Integer, String> emptyMap().merge(map)).isEqualTo(map);
679         } else {
680             assertThat(this.<Integer, String> emptyMap().merge(map)).isSameAs(map);
681         }
682     }
683 
684     // -- merge(Map, BiFunction)
685 
686     @Test
687     public void shouldMergeCollisions() {
688         final Map<Integer, Integer> m1 = emptyIntInt().put(1, 1).put(2, 2);
689         final Map<Integer, Integer> m2 = emptyIntInt().put(1, 2).put(4, 4);
690         final Map<Integer, Integer> m3 = emptyIntInt().put(3, 3).put(4, 4);
691         assertThat(emptyIntInt().merge(m2, Math::max)).isEqualTo(m2);
692         assertThat(m2.merge(emptyIntInt(), Math::max)).isEqualTo(m2);
693         assertThat(m1.merge(m2, Math::max)).isEqualTo(emptyIntInt().put(1, 2).put(2, 2).put(4, 4));
694         assertThat(m1.merge(m3, Math::max)).isEqualTo(emptyIntInt().put(1, 1).put(2, 2).put(3, 3).put(4, 4));
695     }
696 
697     @Test
698     public void shouldReturnSameMapWhenMergeNonEmptyWithEmptyUsingCollisionResolution() {
699         final Map<Integer, Integer> map = mapOf(1, 1, 2, 2, 3, 3);
700         assertThat(map.merge(emptyMap(), Math::max)).isSameAs(map);
701     }
702 
703     @Test
704     public void shouldReturnSameMapWhenMergeEmptyWithNonEmptyUsingCollisionResolution() {
705         final Map<Integer, Integer> map = mapOf(1, 1, 2, 2, 3, 3);
706         if (map.isOrdered()) {
707             assertThat(this.<Integer, Integer> emptyMap().merge(map, Math::max)).isEqualTo(map);
708         } else {
709             assertThat(this.<Integer, Integer> emptyMap().merge(map, Math::max)).isSameAs(map);
710         }
711     }
712 
713     // -- equality
714 
715     @Test
716     public void shouldIgnoreOrderOfEntriesWhenComparingForEquality() {
717         final Map<?, ?> map1 = emptyInt().put(1, 'a').put(2, 'b').put(3, 'c');
718         final Map<?, ?> map2 = emptyInt().put(3, 'c').put(2, 'b').put(1, 'a').remove(2).put(2, 'b');
719         assertThat(map1).isEqualTo(map2);
720     }
721 
722     // -- put
723 
724     @Test
725     public void shouldPutTuple() {
726         assertThat(emptyIntInt().put(Tuple.of(1, 2))).isEqualTo(emptyIntInt().put(1, 2));
727     }
728 
729     @Test
730     public void shouldPutNullKeyIntoMapThatContainsNullKey() {
731         final Map<Integer, String> map = mapOfNullKey(1, "a", null, "b", 2, "c");
732         assertThat(map.put(null, "!")).isEqualTo(mapOfNullKey(1, "a", null, "!", 2, "c"));
733     }
734 
735     @Test
736     public void shouldPutExistingKeyAndNonEqualValue() {
737         final Map<IntMod2, String> map = mapOf(new IntMod2(1), "a");
738 
739         // we need to compare Strings because equals (intentionally) does not work for IntMod2
740         final String actual = map.put(new IntMod2(3), "b").toString();
741         final String expected = map.stringPrefix() + "((3, b))";
742 
743         assertThat(actual).isEqualTo(expected);
744     }
745 
746     @Test
747     public void shouldPutExistingKeyAndEqualValue() {
748         final Map<IntMod2, String> map = mapOf(new IntMod2(1), "a");
749 
750         // we need to compare Strings because equals (intentionally) does not work for IntMod2
751         final String actual = map.put(new IntMod2(3), "a").toString();
752         final String expected = map.stringPrefix() + "((3, a))";
753 
754         assertThat(actual).isEqualTo(expected);
755     }
756 
757     // -- remove
758 
759     @Test
760     public void shouldRemoveKey() {
761         final Map<Integer, Object> src = emptyInt().put(1, 'a').put(2, 'b').put(3, 'c');
762         assertThat(src.remove(2)).isEqualTo(emptyInt().put(1, 'a').put(3, 'c'));
763         assertThat(src.remove(33)).isSameAs(src);
764     }
765 
766     @Test
767     public void shouldRemoveFromMapThatContainsFirstEntryHavingNullKey() {
768         final Map<Integer, String> map = mapOfNullKey(null, "a", 1, "b", 2, "c");
769         assertThat(map.remove(1)).isEqualTo(mapOfNullKey(null, "a", 2, "c"));
770     }
771 
772     // -- removeAll
773 
774     @Test
775     public void shouldRemoveAllKeys() {
776         final Map<Integer, Object> src = emptyInt().put(1, 'a').put(2, 'b').put(3, 'c');
777         assertThat(src.removeAll(io.vavr.collection.List.of(1, 3))).isEqualTo(emptyInt().put(2, 'b'));
778         assertThat(src.removeAll(io.vavr.collection.List.of(33))).isSameAs(src);
779         assertThat(src.removeAll(io.vavr.collection.List.empty())).isSameAs(src);
780     }
781 
782     @Test
783     public void shouldReturnSameMapWhenNonEmptyRemoveAllEmpty() {
784         final Map<Integer, String> map = mapOf(1, "a", 2, "b", 3, "c");
785         assertThat(map.removeAll(io.vavr.collection.List.empty())).isSameAs(map);
786     }
787 
788     @Test
789     public void shouldReturnSameMapWhenEmptyRemoveAllNonEmpty() {
790         final Map<Integer, String> empty = emptyMap();
791         assertThat(empty.removeAll(io.vavr.collection.List.of(1, 2, 3))).isSameAs(empty);
792     }
793 
794     // -- transform
795 
796     @Test
797     public void shouldTransform() {
798         final Map<?, ?> actual = emptyIntInt().put(1, 11).transform(map -> map.put(2, 22));
799         assertThat(actual).isEqualTo(emptyIntInt().put(1, 11).put(2, 22));
800     }
801 
802     // -- unzip
803 
804     @Test
805     public void shouldUnzipIdentityNil() {
806         assertThat(emptyMap().unzip()).isEqualTo(Tuple.of(Stream.empty(), Stream.empty()));
807     }
808 
809     @Test
810     public void shouldUnzipIdentityNonNil() {
811         final Map<Integer, Integer> map = emptyIntInt().put(0, 10).put(1, 11).put(2, 12);
812         final Tuple actual = map.unzip();
813         final Tuple expected = Tuple.of(Stream.of(0, 1, 2), Stream.of(10, 11, 12));
814         assertThat(actual).isEqualTo(expected);
815     }
816 
817     @Test
818     public void shouldUnzipNil() {
819         assertThat(emptyMap().unzip(x -> Tuple.of(x, x))).isEqualTo(Tuple.of(Stream.empty(), Stream.empty()));
820         assertThat(emptyMap().unzip((k, v) -> Tuple.of(Tuple.of(k, v), Tuple.of(k, v))))
821                 .isEqualTo(Tuple.of(Stream.empty(), Stream.empty()));
822     }
823 
824     @Test
825     public void shouldUnzipNonNil() {
826         final Map<Integer, Integer> map = emptyIntInt().put(0, 0).put(1, 1);
827         final Tuple actual = map.unzip(entry -> Tuple.of(entry._1, entry._2 + 1));
828         final Tuple expected = Tuple.of(Stream.of(0, 1), Stream.of(1, 2));
829         assertThat(actual).isEqualTo(expected);
830     }
831 
832     @Test
833     public void shouldUnzip3Nil() {
834         assertThat(emptyMap().unzip3(x -> Tuple.of(x, x, x))).isEqualTo(Tuple.of(Stream.empty(), Stream.empty(), Stream.empty()));
835         assertThat(emptyMap().unzip3((k, v) -> Tuple.of(Tuple.of(k, v), Tuple.of(k, v), Tuple.of(k, v))))
836                 .isEqualTo(Tuple.of(Stream.empty(), Stream.empty(), Stream.empty()));
837     }
838 
839     @Test
840     public void shouldUnzip3NonNil() {
841         final Map<Integer, Integer> map = emptyIntInt().put(0, 0).put(1, 1);
842         final Tuple actual = map.unzip3(entry -> Tuple.of(entry._1, entry._2 + 1, entry._2 + 5));
843         final Tuple expected = Tuple.of(Stream.of(0, 1), Stream.of(1, 2), Stream.of(5, 6));
844         assertThat(actual).isEqualTo(expected);
845     }
846 
847     // -- zip
848 
849     @Test
850     public void shouldZipNils() {
851         final Seq<Tuple2<Tuple2<Integer, Object>, Object>> actual = emptyInt().zip(io.vavr.collection.List.empty());
852         assertThat(actual).isEqualTo(Stream.empty());
853     }
854 
855     @Test
856     public void shouldZipEmptyAndNonNil() {
857         final Seq<Tuple2<Tuple2<Integer, Object>, Integer>> actual = emptyInt().zip(io.vavr.collection.List.of(1));
858         assertThat(actual).isEqualTo(Stream.empty());
859     }
860 
861     @Test
862     public void shouldZipNonEmptyAndNil() {
863         final Seq<Tuple2<Tuple2<Integer, Integer>, Object>> actual = emptyIntInt().put(0, 1).zip(io.vavr.collection.List.empty());
864         assertThat(actual).isEqualTo(Stream.empty());
865     }
866 
867     @Test
868     public void shouldZipNonNilsIfThisIsSmaller() {
869         final Seq<Tuple2<Tuple2<Integer, Integer>, Integer>> actual = emptyIntInt()
870                 .put(0, 0)
871                 .put(1, 1)
872                 .zip(io.vavr.collection.List.of(5, 6, 7));
873         assertThat(actual).isEqualTo(Stream.of(Tuple.of(Tuple.of(0, 0), 5), Tuple.of(Tuple.of(1, 1), 6)));
874     }
875 
876     @Test
877     public void shouldZipNonNilsIfThatIsSmaller() {
878         final Seq<Tuple2<Tuple2<Integer, Integer>, Integer>> actual = emptyIntInt()
879                 .put(0, 0)
880                 .put(1, 1)
881                 .put(2, 2)
882                 .zip(io.vavr.collection.List.of(5, 6));
883         assertThat(actual).isEqualTo(Stream.of(Tuple.of(Tuple.of(0, 0), 5), Tuple.of(Tuple.of(1, 1), 6)));
884     }
885 
886     @Test
887     public void shouldZipNonNilsOfSameSize() {
888         final Seq<Tuple2<Tuple2<Integer, Integer>, Integer>> actual = emptyIntInt()
889                 .put(0, 0)
890                 .put(1, 1)
891                 .put(2, 2)
892                 .zip(io.vavr.collection.List.of(5, 6, 7));
893         assertThat(actual).isEqualTo(
894                 Stream.of(Tuple.of(Tuple.of(0, 0), 5), Tuple.of(Tuple.of(1, 1), 6), Tuple.of(Tuple.of(2, 2), 7)));
895     }
896 
897     @Test(expected = NullPointerException.class)
898     public void shouldThrowIfZipWithThatIsNull() {
899         emptyMap().zip(null);
900     }
901 
902     // -- zipWithIndex
903 
904     @Test
905     public void shouldZipNilWithIndex() {
906         assertThat(emptyMap().zipWithIndex()).isEqualTo(Stream.empty());
907     }
908 
909     @Test
910     public void shouldZipNonNilWithIndex() {
911         final Seq<Tuple2<Tuple2<Integer, Integer>, Integer>> actual = emptyIntInt()
912                 .put(0, 0)
913                 .put(1, 1)
914                 .put(2, 2)
915                 .zipWithIndex();
916         assertThat(actual).isEqualTo(
917                 Stream.of(Tuple.of(Tuple.of(0, 0), 0), Tuple.of(Tuple.of(1, 1), 1), Tuple.of(Tuple.of(2, 2), 2)));
918     }
919 
920     // -- zipAll
921 
922     @Test
923     public void shouldZipAllNils() {
924         final Seq<Tuple2<Tuple2<Integer, Object>, Object>> actual = emptyInt().zipAll(empty(), null, null);
925         assertThat(actual).isEqualTo(Stream.empty());
926     }
927 
928     @Test
929     public void shouldZipAllEmptyAndNonNil() {
930         final Seq<Tuple2<Tuple2<Integer, Object>, Object>> actual = emptyInt().zipAll(io.vavr.collection.List.of(1), null, null);
931         assertThat(actual).isEqualTo(Stream.of(Tuple.of(null, 1)));
932     }
933 
934     @Test
935     public void shouldZipAllNonEmptyAndNil() {
936         final Seq<Tuple2<Tuple2<Integer, Object>, Object>> actual = emptyInt().put(0, 1).zipAll(empty(), null, null);
937         assertThat(actual).isEqualTo(Stream.of(Tuple.of(Tuple.of(0, 1), null)));
938     }
939 
940     @Test
941     public void shouldZipAllNonNilsIfThisIsSmaller() {
942         final Seq<Tuple2<Tuple2<Integer, Integer>, String>> actual = emptyIntInt()
943                 .put(1, 1)
944                 .put(2, 2)
945                 .zipAll(of("a", "b", "c"), Tuple.of(9, 10), "z");
946         final Seq<Tuple2<Tuple2<Object, Object>, String>> expected = Stream.of(Tuple.of(Tuple.of(1, 1), "a"),
947                 Tuple.of(Tuple.of(2, 2), "b"), Tuple.of(Tuple.of(9, 10), "c"));
948         assertThat(actual).isEqualTo(expected);
949     }
950 
951     @Test
952     public void shouldZipAllNonNilsIfThisIsMoreSmaller() {
953         final Seq<Tuple2<Tuple2<Integer, Integer>, String>> actual = emptyIntInt()
954                 .put(1, 1)
955                 .put(2, 2)
956                 .zipAll(of("a", "b", "c", "d"), Tuple.of(9, 10), "z");
957         final Seq<Tuple2<Tuple2<Object, Object>, String>> expected = Stream.of(Tuple.of(Tuple.of(1, 1), "a"),
958                 Tuple.of(Tuple.of(2, 2), "b"), Tuple.of(Tuple.of(9, 10), "c"), Tuple.of(Tuple.of(9, 10), "d"));
959         assertThat(actual).isEqualTo(expected);
960     }
961 
962     @Test
963     public void shouldZipAllNonNilsIfThatIsSmaller() {
964         final Seq<Tuple2<Tuple2<Integer, Integer>, String>> actual = emptyIntInt()
965                 .put(1, 1)
966                 .put(2, 2)
967                 .put(3, 3)
968                 .zipAll(this.of("a", "b"), Tuple.of(9, 10), "z");
969         final Seq<Tuple2<Tuple2<Object, Object>, String>> expected = Stream.of(Tuple.of(Tuple.of(1, 1), "a"),
970                 Tuple.of(Tuple.of(2, 2), "b"), Tuple.of(Tuple.of(3, 3), "z"));
971         assertThat(actual).isEqualTo(expected);
972     }
973 
974     @Test
975     public void shouldZipAllNonNilsIfThatIsMoreSmaller() {
976         final Seq<Tuple2<Tuple2<Integer, Integer>, String>> actual = emptyIntInt()
977                 .put(1, 1)
978                 .put(2, 2)
979                 .put(3, 3)
980                 .put(4, 4)
981                 .zipAll(of("a", "b"), Tuple.of(9, 10), "z");
982         final Seq<Tuple2<Tuple2<Object, Object>, String>> expected = Stream.of(Tuple.of(Tuple.of(1, 1), "a"),
983                 Tuple.of(Tuple.of(2, 2), "b"), Tuple.of(Tuple.of(3, 3), "z"), Tuple.of(Tuple.of(4, 4), "z"));
984         assertThat(actual).isEqualTo(expected);
985     }
986 
987     @Test
988     public void shouldZipAllNonNilsOfSameSize() {
989         final Seq<Tuple2<Tuple2<Integer, Integer>, String>> actual = emptyIntInt()
990                 .put(1, 1)
991                 .put(2, 2)
992                 .put(3, 3)
993                 .zipAll(of("a", "b", "c"), Tuple.of(9, 10), "z");
994         final Seq<Tuple2<Tuple2<Object, Object>, String>> expected = Stream.of(Tuple.of(Tuple.of(1, 1), "a"),
995                 Tuple.of(Tuple.of(2, 2), "b"), Tuple.of(Tuple.of(3, 3), "c"));
996         assertThat(actual).isEqualTo(expected);
997     }
998 
999     @Test(expected = NullPointerException.class)
1000     public void shouldThrowIfZipAllWithThatIsNull() {
1001         emptyMap().zipAll(null, null, null);
1002     }
1003 
1004     // -- special cases
1005 
1006     @Override
1007     public void shouldComputeDistinctOfNonEmptyTraversable() {
1008         final Map<Integer, Object> testee = emptyInt().put(1, 1).put(2, 2).put(3, 3);
1009         assertThat(testee.distinct()).isEqualTo(testee);
1010     }
1011 
1012     @Override
1013     public void shouldReturnSomeTailWhenCallingTailOptionOnNonNil() {
1014         assertThat(of(1, 2, 3).tailOption().get()).isEqualTo(Option.some(of(2, 3)).get());
1015     }
1016 
1017     @Override
1018     public void shouldPreserveSingletonInstanceOnDeserialization() {
1019         final Map<?, ?> obj = deserialize(serialize(emptyMap()));
1020         final boolean actual = obj == emptyMap();
1021         assertThat(actual).isTrue();
1022     }
1023 
1024     @Test
1025     public void shouldSerializeDeserializeNonEmptyMap() {
1026         final Object expected = of('a', 'b', 'c');
1027         final Object actual = deserialize(serialize(expected));
1028         assertThat(actual).isEqualTo(expected);
1029     }
1030 
1031     @Override
1032     public void shouldFoldRightNonNil() {
1033         final String actual = of('a', 'b', 'c').foldRight("", (x, xs) -> x + xs);
1034         final io.vavr.collection.List<String> expected = io.vavr.collection.List.of('a', 'b', 'c').permutations().map(io.vavr.collection.List::mkString);
1035         assertThat(actual).isIn(expected);
1036     }
1037 
1038     // -- forEach
1039 
1040     @Test
1041     public void forEachByKeyValue() {
1042         final Map<Integer, Integer> map = mapOf(1, 2).put(3, 4);
1043         final int[] result = { 0 };
1044         map.forEach((k, v) -> {
1045             result[0] += k + v;
1046         });
1047         assertThat(result[0]).isEqualTo(10);
1048     }
1049 
1050     @Test
1051     public void forEachByTuple() {
1052         final Map<Integer, Integer> map = mapOf(1, 2).put(3, 4);
1053         final int[] result = { 0 };
1054         map.forEach(t -> {
1055             result[0] += t._1 + t._2;
1056         });
1057         assertThat(result[0]).isEqualTo(10);
1058     }
1059 
1060     // -- put with merge function
1061 
1062     @Test
1063     public void putWithWasntPresent() {
1064         final Map<Integer, Integer> map = mapOf(1, 2)
1065                 .put(2, 3, (x, y) -> x + y);
1066         assertThat(map).isEqualTo(emptyIntInt().put(1, 2).put(2, 3));
1067     }
1068 
1069     @Test
1070     public void putWithWasPresent() {
1071         final Map<Integer, Integer> map = mapOf(1, 2)
1072                 .put(1, 3, (x, y) -> x + y);
1073         assertThat(map).isEqualTo(emptyIntInt().put(1, 5));
1074     }
1075 
1076     @Test
1077     public void putWithTupleWasntPresent() {
1078         final Map<Integer, Integer> map = mapOf(1, 2)
1079                 .put(Tuple.of(2, 3), (x, y) -> x + y);
1080         assertThat(map).isEqualTo(emptyIntInt().put(1, 2).put(2, 3));
1081     }
1082 
1083     @Test
1084     public void putWithTupleWasPresent() {
1085         final Map<Integer, Integer> map = mapOf(1, 2)
1086                 .put(Tuple.of(1, 3), (x, y) -> x + y);
1087         assertThat(map).isEqualTo(emptyIntInt().put(1, 5));
1088     }
1089 
1090     @SuppressWarnings("unchecked")
1091     @Test
1092     public void shouldTabulateTheSeq() {
1093         final Function<Number, Tuple2<Long, Float>> f = i -> new Tuple2<>(i.longValue(), i.floatValue());
1094         final Map<Long, Float> map = mapTabulate(3, f);
1095         assertThat(map).isEqualTo(mapOfTuples(new Tuple2<>(0l, 0f), new Tuple2<>(1l, 1f), new Tuple2<>(2l, 2f)));
1096     }
1097 
1098     @SuppressWarnings("unchecked")
1099     @Test
1100     public void shouldTabulateTheSeqCallingTheFunctionInTheRightOrder() {
1101         final LinkedList<Integer> ints = new LinkedList<>(asList(0, 0, 1, 1, 2, 2));
1102         final Function<Integer, Tuple2<Long, Float>> f = i -> new Tuple2<>(ints.remove().longValue(), ints.remove().floatValue());
1103         final Map<Long, Float> map = mapTabulate(3, f);
1104         assertThat(map).isEqualTo(mapOfTuples(new Tuple2<>(0l, 0f), new Tuple2<>(1l, 1f), new Tuple2<>(2l, 2f)));
1105     }
1106 
1107     @Test
1108     public void shouldTabulateTheSeqWith0Elements() {
1109         assertThat(mapTabulate(0, i -> new Tuple2<>(i, i))).isEqualTo(empty());
1110     }
1111 
1112     @Test
1113     public void shouldTabulateTheSeqWith0ElementsWhenNIsNegative() {
1114         assertThat(mapTabulate(-1, i -> new Tuple2<>(i, i))).isEqualTo(empty());
1115     }
1116 
1117     @SuppressWarnings("unchecked")
1118     @Test
1119     public void shouldFillTheSeqCallingTheSupplierInTheRightOrder() {
1120         final LinkedList<Integer> ints = new LinkedList<>(asList(0, 0, 1, 1, 2, 2));
1121         final Supplier<Tuple2<Long, Float>> s = () -> new Tuple2<>(ints.remove().longValue(), ints.remove().floatValue());
1122         final Map<Long, Float> actual = mapFill(3, s);
1123         assertThat(actual).isEqualTo(mapOfTuples(new Tuple2<>(0l, 0f), new Tuple2<>(1l, 1f), new Tuple2<>(2l, 2f)));
1124     }
1125 
1126     @Test
1127     public void shouldFillTheSeqWith0Elements() {
1128         assertThat(mapFill(0, () -> new Tuple2<>(1, 1))).isEqualTo(empty());
1129     }
1130 
1131     @Test
1132     public void shouldFillTheSeqWith0ElementsWhenNIsNegative() {
1133         assertThat(mapFill(-1, () -> new Tuple2<>(1, 1))).isEqualTo(empty());
1134     }
1135 
1136     @SuppressWarnings("unchecked")
1137     @Test
1138     public void mapOfTuplesShouldReturnTheSingletonEmpty() {
1139         if (!emptyMapShouldBeSingleton()) { return; }
1140         assertThat(mapOfTuples()).isSameAs(emptyMap());
1141     }
1142 
1143     @SuppressWarnings("unchecked")
1144     @Test
1145     public void mapOfEntriesShouldReturnTheSingletonEmpty() {
1146         if (!emptyMapShouldBeSingleton()) { return; }
1147         assertThat(mapOfEntries()).isSameAs(emptyMap());
1148     }
1149 
1150     @Test
1151     public void lift() {
1152         final Function1<String, Option<Integer>> lifted = mapOf("A", 1).lift();
1153         assertThat(lifted.apply("A").get()).isEqualTo(1);
1154         assertThat(lifted.apply("a").isEmpty()).isTrue();
1155     }
1156 
1157     @Test
1158     public void withDefaultValue() {
1159         final Function1<String, Integer> withDef = mapOf("A", 1).withDefaultValue(2);
1160         assertThat(withDef.apply("A")).isEqualTo(1);
1161         assertThat(withDef.apply("a")).isEqualTo(2);
1162     }
1163 
1164     @Test
1165     public void withDefault() {
1166         final Function1<String, Integer> withDef = mapOf("A", 1).withDefault(String::length);
1167         assertThat(withDef.apply("A")).isEqualTo(1);
1168         assertThat(withDef.apply("aaa")).isEqualTo(3);
1169     }
1170 
1171     // -- filter
1172 
1173     @Test
1174     public void shouldBiFilterWork() throws Exception {
1175         final Map<Integer, String> src = mapTabulate(20, n -> Tuple.of(n, Integer.toHexString(n)));
1176         final Pattern isDigits = Pattern.compile("^\\d+$");
1177         final Map<Integer, String> dst = src.filter((k, v) -> k % 2 == 0 && isDigits.matcher(v).matches());
1178         assertThat(dst).isEqualTo(emptyIntString().put(0, "0").put(2, "2").put(4, "4").put(6, "6").put(8, "8").put(16, "10").put(18, "12"));
1179     }
1180 
1181     @Test
1182     public void shouldKeyFilterWork() throws Exception {
1183         final Map<Integer, String> src = mapTabulate(20, n -> Tuple.of(n, Integer.toHexString(n)));
1184         final Map<Integer, String> dst = src.filterKeys(k -> k % 2 == 0);
1185         assertThat(dst).isEqualTo(emptyIntString().put(0, "0").put(2, "2").put(4, "4").put(6, "6").put(8, "8").put(10, "a").put(12, "c").put(14, "e").put(16, "10").put(18, "12"));
1186     }
1187 
1188     @Test
1189     public void shouldValueFilterWork() throws Exception {
1190         final Map<Integer, String> src = mapTabulate(10, n -> Tuple.of(n, Integer.toHexString(n)));
1191         final Pattern isDigits = Pattern.compile("^\\d+$");
1192         final Map<Integer, String> dst = src.filterValues(v -> isDigits.matcher(v).matches());
1193         assertThat(dst).isEqualTo(emptyIntString().put(0, "0").put(1, "1").put(2, "2").put(3, "3").put(4, "4").put(5, "5").put(6, "6").put(7, "7").put(8, "8").put(9, "9"));
1194     }
1195 
1196     // -- remove by filter
1197 
1198     @Test
1199     public void shouldBiRemoveWork() throws Exception {
1200         final Map<Integer, String> src = mapTabulate(20, n -> Tuple.of(n, Integer.toHexString(n)));
1201         final Pattern isDigits = Pattern.compile("^\\d+$");
1202         final Map<Integer, String> dst = src.removeAll((k, v) -> k % 2 == 0 && isDigits.matcher(v).matches());
1203         assertThat(dst).isEqualTo(emptyIntString().put(1, "1").put(3, "3").put(5, "5").put(7, "7").put(9, "9").put(10, "a").put(11, "b").put(12, "c").put(13, "d").put(14, "e").put(15, "f").put(17, "11").put(19, "13"));
1204     }
1205 
1206     @Test
1207     public void shouldKeyRemoveWork() throws Exception {
1208         final Map<Integer, String> src = mapTabulate(20, n -> Tuple.of(n, Integer.toHexString(n)));
1209         final Map<Integer, String> dst = src.removeKeys(k -> k % 2 == 0);
1210         assertThat(dst).isEqualTo(emptyIntString().put(1, "1").put(3, "3").put(5, "5").put(7, "7").put(9, "9").put(11, "b").put(13, "d").put(15, "f").put(17, "11").put(19, "13"));
1211     }
1212 
1213     @Test
1214     public void shouldValueRemoveWork() throws Exception {
1215         final Map<Integer, String> src = mapTabulate(20, n -> Tuple.of(n, Integer.toHexString(n)));
1216         final Pattern isDigits = Pattern.compile("^\\d+$");
1217         final Map<Integer, String> dst = src.removeValues(v -> isDigits.matcher(v).matches());
1218         assertThat(dst).isEqualTo(emptyIntString().put(10, "a").put(11, "b").put(12, "c").put(13, "d").put(14, "e").put(15, "f"));
1219     }
1220 
1221     // -- computeIfAbsent
1222 
1223     @Test
1224     public void shouldComputeIfAbsent() {
1225         final Map<Integer, String> map = emptyIntString().put(1, "v");
1226         assertThat(map.computeIfAbsent(1, k -> "b")).isEqualTo(Tuple.of("v", map));
1227         assertThat(map.computeIfAbsent(2, k -> "n")).isEqualTo(Tuple.of("n", emptyIntString().put(1, "v").put(2, "n")));
1228     }
1229 
1230     // -- computeIfAbsent
1231 
1232     @Test
1233     public void shouldComputeIfPresent() {
1234         final Map<Integer, String> map = emptyIntString().put(1, "v");
1235         assertThat(map.computeIfPresent(1, (k, v) -> "b")).isEqualTo(Tuple.of(Option.of("b"), emptyIntString().put(1, "b")));
1236         assertThat(map.computeIfPresent(2, (k, v) -> "n")).isEqualTo(Tuple.of(Option.none(), map));
1237     }
1238 
1239     // -- get with nulls
1240 
1241     @Test
1242     public void shouldReturnOptionOfNullWhenAccessingKeysSetToNull() {
1243         final Map<String, String> map = mapOf("1", null);
1244         assertThat(map.get("1")).isEqualTo(Option.some(null));
1245     }
1246 
1247     @Test
1248     public void shouldReturnOptionOfKeyWhenAccessingPresentKeysInAMapWithNulls() {
1249         final Map<String, String> map = mapOf("1", "a").put("2", null);
1250         assertThat(map.get("1")).isEqualTo(Option.of("a"));
1251     }
1252 
1253     @Test
1254     public void shouldReturnNoneWhenAccessingAbsentKeysInAMapWithNulls() {
1255         final Map<String, String> map = mapOf("1", "a").put("2", null);
1256         assertThat(map.get("3")).isEqualTo(Option.none());
1257     }
1258 
1259     @Test
1260     public void shouldReturnSameInstanceIfReplacingCurrentValueWithNonExistingKey() {
1261         final Map<Integer, String> map = mapOf(1, "a", 2, "b");
1262         final Map<Integer, String> actual = map.replaceValue(3, "?");
1263         assertThat(actual).isSameAs(map);
1264     }
1265 
1266     @Test
1267     public void shouldReplaceCurrentValueForExistingKey() {
1268         final Map<Integer, String> map = mapOf(1, "a", 2, "b");
1269         final Map<Integer, String> actual = map.replaceValue(2, "c");
1270         final Map<Integer, String> expected = mapOf(1, "a", 2, "c");
1271         assertThat(actual).isEqualTo(expected);
1272     }
1273 
1274     @Test
1275     public void shouldReplaceCurrentValueForExistingKeyAndEqualOldValue() {
1276         final Map<Integer, String> map = mapOf(1, "a", 2, "b");
1277         final Map<Integer, String> actual = map.replace(2, "b", "c");
1278         final Map<Integer, String> expected = mapOf(1, "a", 2, "c");
1279         assertThat(actual).isEqualTo(expected);
1280     }
1281 
1282     @Test
1283     public void shouldReturnSameInstanceForExistingKeyAndNonEqualOldValue() {
1284         final Map<Integer, String> map = mapOf(1, "a", 2, "b");
1285         final Map<Integer, String> actual = map.replace(2, "d", "c");
1286         assertThat(actual).isSameAs(map);
1287     }
1288 
1289     @Test
1290     public void shouldReturnSameInstanceIfReplacingCurrentValueWithOldValueWithNonExistingKey() {
1291         final Map<Integer, String> map = mapOf(1, "a", 2, "b");
1292         final Map<Integer, String> actual = map.replace(3, "?", "!");
1293         assertThat(actual).isSameAs(map);
1294     }
1295 
1296     @Test
1297     public void shouldReplaceAllValuesWithFunctionResult() {
1298         final Map<Integer, String> map = mapOf(1, "a", 2, "b");
1299         final Map<Integer, String> actual = map.replaceAll((integer, s) -> s + integer);
1300         final Map<Integer, String> expected = mapOf(1, "a1", 2, "b2");
1301         assertThat(actual).isEqualTo(expected);
1302     }
1303 
1304     @Test
1305     public void shouldGetValueOfNullKeyWhenPutFirstHavingTwoEntries() {
1306         final Map<Integer, String> map = mapOfNullKey(null, "a", 2, "b");
1307         assertThat(map.get(null)).isEqualTo(Some("a"));
1308     }
1309 
1310     @Test
1311     public void shouldGetValueOfNullKeyWhenPutLastHavingTwoEntries() {
1312         final Map<Integer, String> map = mapOfNullKey(1, "a", null, "b");
1313         assertThat(map.get(null)).isEqualTo(Some("b"));
1314     }
1315 
1316     @Test
1317     public void shouldGetAPresentNullValueWhenPutFirstHavingTwoEntries() {
1318         final Map<Integer, String> map = mapOf(1, null, 2, "b");
1319         assertThat(map.get(1)).isEqualTo(Some(null));
1320     }
1321 
1322     @Test
1323     public void shouldGetAPresentNullValueWhenPutLastHavingTwoEntries() {
1324         final Map<Integer, String> map = mapOf(1, "a", 2, null);
1325         assertThat(map.get(2)).isEqualTo(Some(null));
1326     }
1327 
1328     // -- getOrElse
1329 
1330     @Test
1331     public void shouldReturnDefaultValue() {
1332         final Map<String, String> map = mapOf("1", "a").put("2", "b");
1333         assertThat(map.getOrElse("3", "3")).isEqualTo("3");
1334     }
1335 
1336     // -- spliterator
1337 
1338     @Test
1339     public void shouldHaveSizedSpliterator() {
1340         assertThat(of(1, 2, 3).spliterator().hasCharacteristics(Spliterator.SIZED | Spliterator.SUBSIZED)).isTrue();
1341     }
1342 
1343     @Test
1344     public void shouldHaveDistinctSpliterator() {
1345         assertThat(of(1, 2, 3).spliterator().hasCharacteristics(Spliterator.DISTINCT)).isTrue();
1346     }
1347 
1348     @Test
1349     public void shouldReturnSizeWhenSpliterator() {
1350         assertThat(of(1, 2, 3).spliterator().getExactSizeIfKnown()).isEqualTo(3);
1351     }
1352 
1353     @Override
1354     @Test
1355     @SuppressWarnings("unchecked")
1356     public void shouldPartitionIntsInOddAndEvenHavingOddAndEvenNumbers() {
1357         assertThat(of(1, 2, 3, 4).partition(i -> i % 2 != 0))
1358                 .isEqualTo(Tuple.of(mapOfTuples(Tuple.of(0, 1), Tuple.of(2, 3)),
1359                         mapOfTuples(Tuple.of(1, 2), Tuple.of(3, 4))));
1360     }
1361 
1362     @Override
1363     @Test
1364     @SuppressWarnings("unchecked")
1365     public void shouldSpanNonNil() {
1366         assertThat(of(0, 1, 2, 3).span(i -> i < 2))
1367                 .isEqualTo(Tuple.of(mapOfTuples(Tuple.of(0, 0), Tuple.of(1, 1)),
1368                 mapOfTuples(Tuple.of(2, 2), Tuple.of(3, 3))));
1369     }
1370 
1371     @Override
1372     @Test
1373     @SuppressWarnings("unchecked")
1374     public void shouldSpanAndNotTruncate() {
1375         assertThat(of(1, 1, 2, 2, 3, 3).span(x -> x % 2 == 1))
1376                 .isEqualTo(Tuple.of(mapOfTuples(Tuple.of(0,1), Tuple.of(1, 1)),
1377                         mapOfTuples(Tuple.of(2, 2), Tuple.of(3, 2),
1378                                 Tuple.of(4, 3), Tuple.of(5, 3))));
1379         assertThat(of(1, 1, 2, 2, 4, 4).span(x -> x == 1))
1380                 .isEqualTo(Tuple.of(mapOfTuples(Tuple.of(0,1), Tuple.of(1, 1)),
1381                         mapOfTuples(Tuple.of(2, 2), Tuple.of(3, 2),
1382                         Tuple.of(4, 4), Tuple.of(5, 4))));
1383     }
1384 
1385     @Override
1386     @Test
1387     public void shouldNonNilGroupByIdentity() {
1388         final Map<?, ?> actual = of('a', 'b', 'c').groupBy(Function.identity());
1389         final Map<?, ?> expected = io.vavr.collection.LinkedHashMap.empty().put('a', mapOf(0, 'a')).put('b', mapOf(1,'b'))
1390                 .put('c', mapOf(2,'c'));
1391         assertThat(actual).isEqualTo(expected);
1392     }
1393 
1394 }